home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-10-13 | 31.2 KB | 1,179 lines |
- import java.applet.Applet;
- import java.awt.Image;
- import java.awt.Graphics;
- import java.awt.Rectangle;
- import java.util.StringTokenizer;
- import java.util.Vector;
- import java.util.Hashtable;
- import java.net.URL;
- import java.awt.image.*;
- import java.net.MalformedURLException;
-
- /**
- * An extensible ImageMap applet class.
- * The active areas on the image are controlled by ImageArea classes
- * that can be dynamically loaded over the net.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- public class ImageMap extends Applet {
- /**
- * The unhighlighted image being mapped.
- */
- Image baseImage;
-
- /**
- * The list of image area handling objects;
- */
- ImageMapArea areas[];
-
- /**
- * The primary highlight mode to be used.
- */
- static final int BRIGHTER = 0;
- static final int DARKER = 1;
-
- int hlmode = BRIGHTER;
-
- /**
- * The percentage of highlight to apply for the primary highlight mode.
- */
- int hlpercent = 50;
-
- /**
- * Get a rectangular region of the baseImage highlighted according to
- * the primary highlight specification.
- */
- Image getHighlight(int x, int y, int w, int h) {
- return getHighlight(x, y, w, h, hlmode, hlpercent);
- }
-
- /**
- * Get a rectangular region of the baseImage with a specific highlight.
- */
- Image getHighlight(int x, int y, int w, int h, int mode, int percent) {
- return getHighlight(x, y, w, h, new HighlightFilter(mode == BRIGHTER,
- percent));
- }
-
- /**
- * Get a rectangular region of the baseImage modified by an image filter.
- */
- Image getHighlight(int x, int y, int w, int h, ImageFilter filter) {
- Image cropped = makeImage(baseImage, new CropImageFilter(x, y, w, h));
- return makeImage(cropped, filter);
- }
-
- /**
- * Make the primary highlighted version of the baseImage.
- */
- Image makeImage(Image orig, ImageFilter filter) {
- return createImage(new FilteredImageSource(orig.getSource(), filter));
- }
-
- /**
- * Parse a string representing the desired highlight to be applied.
- */
- void parseHighlight(String s) {
- if (s == null) {
- return;
- }
- if (s.startsWith("brighter")) {
- hlmode = BRIGHTER;
- if (s.length() > "brighter".length()) {
- hlpercent = Integer.parseInt(s.substring("brighter".length()));
- }
- } else if (s.startsWith("darker")) {
- hlmode = DARKER;
- if (s.length() > "darker".length()) {
- hlpercent = Integer.parseInt(s.substring("darker".length()));
- }
- }
- }
-
- /**
- * Initialize the applet. Get attributes.
- *
- * Initialize the ImageAreas.
- * Each ImageArea is a subclass of the class ImageArea, and is
- * specified with an attribute of the form:
- * areaN=ImageAreaClassName,arguments...
- * The ImageAreaClassName is parsed off and a new instance of that
- * class is created. The initializer for that class is passed a
- * reference to the applet and the remainder of the attribute
- * string, from which the class should retrieve any information it
- * needs about the area it controls and the actions it needs to
- * take within that area.
- */
- public void init() {
- String s;
-
- parseHighlight(getParameter("highlight"));
- baseImage = getImage(getDocumentBase(), getParameter("img"));
- Vector areaVec = new Vector();
- int num = 1;
- while (true) {
- ImageMapArea newArea;
- s = getParameter("area"+num);
- if (s == null) {
- // Try rect for backwards compatibility.
- s = getParameter("rect"+num);
- if (s == null) {
- break;
- }
- String url = getParameter("href"+num);
- if (url != null)
- s += "," + url;
- newArea = new HrefArea();
- } else {
- int classend = s.indexOf(",");
- try {
- String name = s.substring(0, classend);
- newArea = (ImageMapArea) Class.forName(name).newInstance();
- } catch (Exception e) {
- e.printStackTrace();
- break;
- }
- s = s.substring(classend+1);
- }
- newArea.init(this, s);
- areaVec.addElement(newArea);
- num++;
- }
- areas = new ImageMapArea[areaVec.size()];
- areaVec.copyInto(areas);
- checkSize();
- }
-
- /**
- * Check the size of this applet while the image is being loaded.
- */
- synchronized void checkSize() {
- int w = baseImage.getWidth(this);
- int h = baseImage.getHeight(this);
- if (w > 0 && h > 0) {
- resize(w, h);
- repaintrect.x = repaintrect.y = 0;
- repaintrect.width = w;
- repaintrect.height = h;
- fullrepaint = true;
- repaint();
- }
- }
-
- private boolean fullrepaint = false;
- private Rectangle repaintrect = new Rectangle();
- private long lastupdate = 0;
- private final static long UPDATERATE = 100;
-
- /**
- * Handle updates from images being loaded.
- */
- public boolean imageUpdate(Image img, int infoflags,
- int x, int y, int width, int height) {
- if ((infoflags & (WIDTH | HEIGHT)) != 0) {
- checkSize();
- }
- if ((infoflags & (SOMEBITS | FRAMEBITS | ALLBITS)) != 0) {
- repaint(((infoflags & (FRAMEBITS | ALLBITS)) != 0)
- ? 0 : UPDATERATE,
- x, y, width, height);
- }
- return (infoflags & (ALLBITS | ERROR)) == 0;
- }
-
- /**
- * Paint the image and all active highlights.
- */
- public void paint(Graphics g) {
- synchronized(this) {
- if (fullrepaint) {
- g = g.create();
- g.clipRect(repaintrect.x, repaintrect.y,
- repaintrect.width, repaintrect.height);
- fullrepaint = false;
- }
- }
- if (baseImage == null) {
- return;
- }
- g.drawImage(baseImage, 0, 0, this);
- if (areas != null) {
- for (int i = areas.length; --i >= 0; ) {
- if (areas[i].active || areas[i].entered) {
- areas[i].setState(g, areas[i].entered);
- }
- }
- }
- }
-
- /**
- * Update the active highlights on the image.
- */
- public void update(Graphics g) {
- if (fullrepaint) {
- paint(g);
- return;
- }
- if (baseImage == null) {
- return;
- }
- g.drawImage(baseImage, 0, 0, this);
- if (areas == null) {
- return;
- }
- // First unhighlight all of the deactivated areas
- for (int i = areas.length; --i >= 0; ) {
- if (areas[i].active && !areas[i].entered) {
- areas[i].setState(g, false);
- }
- }
- // Then highlight all of the activated areas
- for (int i = areas.length; --i >= 0; ) {
- if (areas[i].entered) {
- areas[i].setState(g, true);
- }
- }
- }
-
- /**
- * Make sure that no ImageAreas are highlighted.
- */
- public void mouseExit() {
- boolean changed = false;
-
- for (int i = 0; i < areas.length; i++) {
- if (areas[i].active) {
- areas[i].entered = false;
- changed = true;
- }
- }
- if (changed) {
- repaint();
- }
- }
-
- /**
- * Find the ImageAreas that the mouse is in.
- */
- public boolean mouseMove(java.awt.Event evt, int x, int y) {
- boolean changed = false;
- boolean propagate = true;
-
- for (int i = 0; i < areas.length; i++) {
- if (areas[i].inside(x, y)) {
- areas[i].entered = propagate;
- if (areas[i].terminal) {
- propagate = false;
- }
- } else {
- areas[i].entered = false;
- }
-
- if (areas[i].active != areas[i].entered) {
- changed = true;
- }
- }
-
- if (changed) {
- repaint();
- }
-
- return true;
- }
-
- int pressX;
- int pressY;
-
- /**
- * Inform all active ImageAreas of a mouse press.
- */
- public boolean mouseDown(java.awt.Event evt, int x, int y) {
- pressX = x;
- pressY = y;
-
- for (int i = 0; i < areas.length; i++) {
- if (areas[i].inside(x, y)) {
- areas[i].press(x, y);
- if (areas[i].terminal) {
- break;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Inform all active ImageAreas of a mouse release.
- * Only those areas that were inside the original mouseDown()
- * are informed of the mouseUp.
- */
- public boolean mouseUp(java.awt.Event evt, int x, int y) {
- for (int i = 0; i < areas.length; i++) {
- if (areas[i].inside(pressX, pressY)) {
- areas[i].lift(x, y);
- if (areas[i].terminal) {
- break;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Inform all active ImageAreas of a mouse drag.
- * Only those areas that were inside the original mouseDown()
- * are informed of the mouseUp.
- */
- public boolean mouseDrag(java.awt.Event evt, int x, int y) {
- mouseMove(evt, x, y);
- for (int i = 0; i < areas.length; i++) {
- if (areas[i].inside(pressX, pressY)) {
- areas[i].drag(x, y);
- if (areas[i].terminal) {
- break;
- }
- }
- }
-
- return true;
- }
- }
-
- /**
- * The base ImageArea class.
- * This class performs the basic functions that most ImageArea
- * classes will need and delegates specific actions to the subclasses.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- class ImageMapArea implements ImageObserver {
- /** The applet parent that contains this ImageArea. */
- ImageMap parent;
- /** The X location of the area (if rectangular). */
- int X;
- /** The Y location of the area (if rectangular). */
- int Y;
- /** The size().width of the area (if rectangular). */
- int W;
- /** The size().height of the area (if rectangular). */
- int H;
- /**
- * This flag indicates whether the user was in this area during the
- * last scan of mouse locations.
- */
- boolean entered = false;
- /** This flag indicates whether the area is currently highlighted. */
- boolean active = false;
- /**
- * This flag indicates whether the area is terminal. Terminal areas
- * prevent any areas which are under them from being activated when
- * the mouse is inside them. Some areas may wish to change this to
- * false so that they can augment other areas that they are on top of.
- */
- boolean terminal = true;
- /**
- * This is the default highlight image if no special effects are
- * needed to draw the highlighted image. It is created by the
- * default "makeImages()" method.
- */
- Image hlImage;
-
- /**
- * Initialize this ImageArea as called from the applet.
- * If the subclass does not override this initializer, then it
- * will perform the basic functions of setting the parent applet
- * and parsing out 4 numbers from the argument string which specify
- * a rectangular region for the ImageArea to act on.
- * The remainder of the argument string is passed to the handleArg()
- * method for more specific handling by the subclass.
- */
- public void init(ImageMap parent, String args) {
- this.parent = parent;
- StringTokenizer st = new StringTokenizer(args, ", ");
- X = Integer.parseInt(st.nextToken());
- Y = Integer.parseInt(st.nextToken());
- W = Integer.parseInt(st.nextToken());
- H = Integer.parseInt(st.nextToken());
- if (st.hasMoreTokens()) {
- // hasMoreTokens() Skips the trailing comma
- handleArg(st.nextToken(""));
- } else {
- handleArg(null);
- }
- makeImages();
- }
-
- /**
- * This method handles the remainder of the argument string after
- * the standard initializer has parsed off the 4 rectangular
- * parameters. If the subclass does not override this method,
- * the remainder will be ignored.
- */
- public void handleArg(String s) {
- }
-
- /**
- * This method sets the image to be used to render the ImageArea
- * when it is highlighted.
- */
- public void setHighlight(Image img) {
- hlImage = img;
- }
-
- /**
- * This method handles the construction of the various images
- * used to highlight this particular ImageArea when the user
- * interacts with it.
- */
- public void makeImages() {
- setHighlight(parent.getHighlight(X, Y, W, H));
- }
-
- /**
- * This method tests to see if a point is inside this ImageArea.
- * The standard method assumes a rectangular area as parsed by
- * the standard initializer. If a more complex area is required
- * then this method will have to be overridden by the subclass.
- */
- public boolean inside(int x, int y) {
- return (x >= X && x < (X + W) && y >= Y && y < (Y + H));
- }
-
- /**
- * This utility method draws a rectangular subset of a highlight
- * image.
- */
- public void drawImage(Graphics g, Image img, int imgx, int imgy,
- int x, int y, int w, int h) {
- Graphics ng = g.create();
- ng.clipRect(x, y, w, h);
- ng.drawImage(img, imgx, imgy, this);
- }
-
- /**
- * This method handles the updates from drawing the images.
- */
- public boolean imageUpdate(Image img, int infoflags,
- int x, int y, int width, int height) {
- if (img == hlImage) {
- return parent.imageUpdate(img, infoflags, x + X, y + Y,
- width, height);
- } else {
- return false;
- }
- }
-
- /**
- * This utility method shows a string in the status bar.
- */
- public void showStatus(String msg) {
- parent.getAppletContext().showStatus(msg);
- }
-
- /**
- * This utility method tells the browser to visit a URL.
- */
- public void showDocument(URL u) {
- parent.getAppletContext().showDocument(u);
- }
-
- /**
- * This method highlights the specified area when the user enters
- * it with his mouse. The standard highlight method is to replace
- * the indicated rectangular area of the image with the primary
- * highlighted image.
- */
- public void highlight(Graphics g, boolean on) {
- if (on) {
- g.drawImage(hlImage, X, Y, this);
- } else {
- drawImage(g, parent.baseImage, 0, 0, X, Y, W, H);
- }
- }
-
- /**
- * This method changes the active state of the ImageArea, which
- * indicates whether the user is currently "inside" this area.
- * It turns around and calls the highlight method which is likely
- * to have been overridden by subclasses seeking a custom highlight.
- */
- public void setState(Graphics g, boolean on) {
- highlight(g, on);
- active = on;
- }
-
- /**
- * The press method is called when the user presses the mouse
- * button inside the ImageArea. The location is supplied, but
- * the standard implementation is to call the overloaded method
- * with no arguments.
- */
- public void press(int x, int y) {
- press();
- }
-
- /**
- * The overloaded press method is called when the user presses the
- * mouse button inside the ImageArea. This method can be overridden
- * if the ImageArea does not need to know the location of the press.
- */
- public void press() {
- }
-
- /**
- * The lift method is called when the user releases the mouse button.
- * The location is supplied, but the standard implementation is to
- * call the overloaded method with no arguments. Only those ImageAreas
- * that were informed of a press will be informed of the corresponding
- * release.
- */
- public void lift(int x, int y) {
- lift();
- }
-
- /**
- * The overloaded lift method is called when the user releases the
- * mouse button. This method can be overridden if the ImageArea
- * does not need to know the location of the release.
- */
- public void lift() {
- }
-
- /**
- * The drag method is called when the user moves the mouse while
- * the button is pressed. Only those ImageAreas that were informed
- * of a press will be informed of the corresponding mouse movements.
- */
- public void drag(int x, int y) {
- }
- }
-
- /**
- * The classic "Fetch a URL" ImageArea class.
- * This class extends the basic ImageArea Class to fetch a URL when
- * the user clicks in the area.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- class HrefArea extends ImageMapArea {
- /** The URL to be fetched when the user clicks on this area. */
- URL anchor;
-
- /**
- * The argument string is the URL to be fetched.
- */
- public void handleArg(String arg) {
- try {
- anchor = new URL(parent.getDocumentBase(), arg);
- } catch (MalformedURLException e) {
- anchor = null;
- }
- }
-
- /**
- * The status message area is updated to show the destination URL.
- * The default graphics highlight feedback is used.
- */
- public void highlight(Graphics g, boolean on) {
- super.highlight(g, on);
- showStatus((on && anchor != null)
- ? "Go To " + anchor.toExternalForm()
- : null);
- }
-
- /**
- * The new URL is fetched when the user releases the mouse button
- * only if they are still in the area.
- */
- public void lift(int x, int y) {
- if (inside(x, y) && anchor != null) {
- showDocument(anchor);
- }
- // Note that we should not be active, so no repaint is necessary.
- }
- }
-
- /**
- * An audio feedback ImageArea class.
- * This class extends the basic ImageArea Class to play a sound each
- * time the user enters the area.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- class SoundArea extends ImageMapArea {
- /** The URL of the sound to be played. */
- String sound;
-
- /**
- * The argument is the URL of the sound to be played.
- * This method also sets this type of area to be non-terminal.
- */
- public void handleArg(String arg) {
- sound = arg;
- terminal = false;
- }
-
- /**
- * The highlight method plays the sound in addition to the usual
- * graphical highlight feedback.
- */
- public void highlight(Graphics g, boolean on) {
- if (on && !active) {
- parent.play(parent.getDocumentBase(), sound);
- }
- super.highlight(g, on);
- }
- }
-
- /**
- * An click feedback ImageArea class.
- * This class extends the basic ImageArea Class to show the locations
- * of clicks in the image in the status message area. This utility
- * ImageArea class is useful when setting up ImageMaps.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- class ClickArea extends ImageMapArea {
- /** The X location of the last mouse press. */
- int startx;
- /** The Y location of the last mouse press. */
- int starty;
-
- /**
- * The argument is ignored, but we use this method to set this type
- * of area to be non-terminal.
- */
- public void handleArg(String arg) {
- terminal = false;
- }
-
- /** This class overrides the highlight method to prevent highlighting. */
- public void highlight(Graphics g, boolean on) {
- }
-
- String ptstr(int x, int y) {
- return "("+x+", "+y+")";
- }
-
- /**
- * When the user presses the mouse button, start showing coordinate
- * feedback in the status message line.
- */
- public void press(int x, int y) {
- showStatus("Clicked at "+ptstr(x, y));
- startx = x;
- starty = y;
- }
-
- /**
- * Update the coordinate feedback every time the user moves the mouse
- * while he has the button pressed.
- */
- public void drag(int x, int y) {
- showStatus("Rectangle from "+ptstr(startx, starty)
- +" to "+ptstr(x, y)
- +" is "+(x-startx)+"x"+(y-starty));
- }
-
- /**
- * Update the coordinate feedback one last time when the user releases
- * the mouse button.
- */
- public void lift(int x, int y) {
- drag(x, y);
- }
- }
-
- /**
- * A message feedback ImageArea class.
- * This class extends the basic ImageArea Class to show the a given
- * message in the status message area when the user enters this area.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- class NameArea extends ImageMapArea {
- /** The string to be shown in the status message area. */
- String name;
-
- /**
- * The argument is the string to be displayed in the status message
- * area. This method also sets this type of area to be non-terminal.
- */
- public void handleArg(String arg) {
- name = arg;
- terminal = false;
- }
-
- /**
- * The highlight method displays the message in addition to the usual
- * graphical highlight feedback.
- */
- public void highlight(Graphics g, boolean on) {
- super.highlight(g, on);
- showStatus(on ? name : null);
- }
-
- }
-
- /**
- * An improved "Fetch a URL" ImageArea class.
- * This class extends the basic ImageArea Class to fetch a URL when
- * the user clicks in the area. In addition, special custom highlights
- * are used to make the area look and feel like a 3-D button.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- class HrefButtonArea extends ImageMapArea {
- /** The URL to be fetched when the user clicks on this area. */
- URL anchor;
- /** The highlight image for when the button is "UP". */
- Image upImage;
- /** The highlight image for when the button is "DOWN". */
- Image downImage;
- /** This flag indicates if the "button" is currently pressed. */
- boolean pressed = false;
- /** The border size for the 3-D effect. */
- int border = 5;
-
- /**
- * The argument string is the URL to be fetched.
- * This method also constructs the various highlight images needed
- * to achieve the 3-D effect.
- */
- public void handleArg(String arg) {
- try {
- anchor = new URL(parent.getDocumentBase(), arg);
- } catch (MalformedURLException e) {
- anchor = null;
- }
- if (border * 2 > W || border * 2 > H) {
- border = Math.min(W, H) / 2;
- }
- }
-
- public void makeImages() {
- upImage = parent.getHighlight(X, Y, W, H,
- new ButtonFilter(false,
- parent.hlpercent,
- border, W, H));
- downImage = parent.getHighlight(X, Y, W, H,
- new ButtonFilter(true,
- parent.hlpercent,
- border, W, H));
- }
-
- public boolean imageUpdate(Image img, int infoflags,
- int x, int y, int width, int height) {
- if (img == (pressed ? downImage : upImage)) {
- return parent.imageUpdate(img, infoflags, x + X, y + Y,
- width, height);
- } else {
- return (img == downImage || img == upImage);
- }
- }
-
- /**
- * The status message area is updated to show the destination URL.
- * The graphical highlight is achieved using the ButtonFilter.
- */
- public void highlight(Graphics g, boolean on) {
- if (on) {
- setHighlight(pressed ? downImage : upImage);
- }
- super.highlight(g, on);
- showStatus((on && anchor != null)
- ? "Go To " + anchor.toExternalForm()
- : null);
- }
-
- /**
- * Since the highlight changes when the button is pressed, we need
- * to record the "pressed" state and induce a repaint.
- */
- public void press() {
- parent.repaint();
- pressed = true;
- }
-
- /**
- * The new URL is fetched when the user releases the mouse button
- * only if they are still in the area.
- */
- public void lift(int x, int y) {
- pressed = false;
- parent.repaint();
- if (inside(x, y) && anchor != null) {
- showDocument(anchor);
- }
- }
- }
-
- /**
- * An improved, round, "Fetch a URL" ImageArea class.
- * This class extends the HrefButtonArea Class to make the 3D button
- * a rounded ellipse. All of the same feedback and operational
- * charactistics as the HrefButtonArea apply.
- *
- * @author Jim Graham
- * @version %I%, %G%
- */
- class RoundHrefButtonArea extends HrefButtonArea {
- public void makeImages() {
- upImage = parent.getHighlight(X, Y, W, H,
- new RoundButtonFilter(false,
- parent.hlpercent,
- border, W, H));
- downImage = parent.getHighlight(X, Y, W, H,
- new RoundButtonFilter(true,
- parent.hlpercent,
- border, W, H));
- }
- }
-
- class HighlightFilter extends RGBImageFilter {
- boolean brighter;
- int percent;
-
- public HighlightFilter(boolean b, int p) {
- brighter = b;
- percent = p;
- canFilterIndexColorModel = true;
- }
-
- public int filterRGB(int x, int y, int rgb) {
- int r = (rgb >> 16) & 0xff;
- int g = (rgb >> 8) & 0xff;
- int b = (rgb >> 0) & 0xff;
- if (brighter) {
- r = (255 - ((255 - r) * (100 - percent) / 100));
- g = (255 - ((255 - g) * (100 - percent) / 100));
- b = (255 - ((255 - b) * (100 - percent) / 100));
- } else {
- r = (r * (100 - percent) / 100);
- g = (g * (100 - percent) / 100);
- b = (b * (100 - percent) / 100);
- }
- if (r < 0) r = 0;
- if (r > 255) r = 255;
- if (g < 0) g = 0;
- if (g > 255) g = 255;
- if (b < 0) b = 0;
- if (b > 255) b = 255;
- return (rgb & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
- }
- }
-
- class ButtonFilter extends RGBImageFilter {
- boolean pressed;
- int defpercent;
- int border;
- int width;
- int height;
-
- ColorModel models[] = new ColorModel[7];
- ColorModel origbuttonmodel;
-
- public ButtonFilter(boolean press, int p, int b, int w, int h) {
- pressed = press;
- defpercent = p;
- border = b;
- width = w;
- height = h;
- }
-
- public void setHints(int hints) {
- super.setHints(hints & (~ImageConsumer.COMPLETESCANLINES));
- }
-
- public void setColorModel(ColorModel model) {
- if (model instanceof IndexColorModel && true) {
- IndexColorModel icm = (IndexColorModel) model;
- models[0] = filterIndexColorModel(icm, false, false, 0);
- models[1] = filterIndexColorModel(icm, true, !pressed, defpercent);
- models[2] = null;
- if (pressed) {
- models[3] = filterIndexColorModel(icm, true, false,
- defpercent/2);
- } else {
- models[3] = models[0];
- }
- models[4] = null;
- models[5] = filterIndexColorModel(icm, true, pressed, defpercent);
- models[6] = models[0];
- origbuttonmodel = model;
- consumer.setColorModel(models[3]);
- } else {
- super.setColorModel(model);
- }
- }
-
- public IndexColorModel filterIndexColorModel(IndexColorModel icm,
- boolean opaque,
- boolean brighter,
- int percent) {
- byte r[] = new byte[256];
- byte g[] = new byte[256];
- byte b[] = new byte[256];
- byte a[] = new byte[256];
- int mapsize = icm.getMapSize();
- icm.getReds(r);
- icm.getGreens(g);
- icm.getBlues(b);
- if (opaque) {
- icm.getAlphas(a);
- for (int i = 0; i < mapsize; i++) {
- int rgb = filterRGB(icm.getRGB(i), brighter, percent);
- a[i] = (byte) (rgb >> 24);
- r[i] = (byte) (rgb >> 16);
- g[i] = (byte) (rgb >> 8);
- b[i] = (byte) (rgb >> 0);
- }
- }
- return new IndexColorModel(icm.getPixelSize(), mapsize, r, g, b, a);
- }
-
- /**
- * Define the ranges of varying highlight for the button.
- * ranges is an array of 8 values which split up a scanline into
- * 7 different regions of highlighting effect:
- *
- * ranges[0-1] = area outside of left edge of button
- * ranges[1-2] = area inside UpperLeft highlight region left of center
- * ranges[2-3] = area requiring custom highlighting left of center
- * ranges[3-4] = area inside center of button
- * ranges[4-5] = area requiring custom highlighting right of center
- * ranges[5-6] = area inside LowerRight highlight region right of center
- * ranges[6-7] = area outside of right edge of button
- *
- * Note that ranges[0-1] and ranges[6-7] are empty where the edges of
- * the button touch the left and right edges of the image (everywhere
- * on a square button) and ranges[2-3] and ranges[4-5] are only nonempty
- * in those regions where the UpperLeft highlighting has leaked over
- * the "top" of the button onto parts of its right edge or where the
- * LowerRight highlighting has leaked under the "bottom" of the button
- * onto parts of its left edge (can't happen on square buttons, happens
- * occasionally on round buttons).
- */
- public void buttonRanges(int y, int ranges[]) {
- ranges[0] = ranges[1] = 0;
- if (y < border) {
- ranges[2] = ranges[3] = ranges[4] = ranges[5] = width - y;
- } else if (y > height - border) {
- ranges[2] = ranges[3] = ranges[4] = ranges[5] = height - y;
- } else {
- ranges[2] = ranges[3] = border;
- ranges[4] = ranges[5] = width - border;
- }
- ranges[6] = ranges[7] = width;
- }
-
- public void setPixels(int x, int y, int w, int h,
- ColorModel model, byte pixels[], int off,
- int scansize) {
- if (model == origbuttonmodel) {
- int ranges[] = new int[8];
- int x2 = x + w;
- for (int cy = y; cy < y + h; cy++) {
- buttonRanges(cy, ranges);
- for (int i = 0; i < 7; i++) {
- if (x2 > ranges[i] && x < ranges[i+1]) {
- int cx1 = Math.max(x, ranges[i]);
- int cx2 = Math.min(x2, ranges[i+1]);
- if (models[i] == null) {
- super.setPixels(cx1, cy, cx2 - cx1, 1,
- model, pixels,
- off + (cx1 - x), scansize);
- } else {
- if (cx1 < cx2) {
- consumer.setPixels(cx1, cy, cx2 - cx1, 1,
- models[i], pixels,
- off + (cx1 - x), scansize);
- }
- }
- }
- }
- off += scansize;
- }
- } else {
- super.setPixels(x, y, w, h, model, pixels, off, scansize);
- }
- }
-
- public int filterRGB(int x, int y, int rgb) {
- boolean brighter;
- int percent;
- if ((x < border && y < height - x) || (y < border && x < width - y)) {
- brighter = !pressed;
- percent = defpercent;
- } else if (x >= width - border || y >= height - border) {
- brighter = pressed;
- percent = defpercent;
- } else if (pressed) {
- brighter = false;
- percent = defpercent / 2;
- } else {
- return rgb & 0x00ffffff;
- }
- return filterRGB(rgb, brighter, percent);
- }
-
- public int filterRGB(int rgb, boolean brighter, int percent) {
- int r = (rgb >> 16) & 0xff;
- int g = (rgb >> 8) & 0xff;
- int b = (rgb >> 0) & 0xff;
- if (brighter) {
- r = (255 - ((255 - r) * (100 - percent) / 100));
- g = (255 - ((255 - g) * (100 - percent) / 100));
- b = (255 - ((255 - b) * (100 - percent) / 100));
- } else {
- r = (r * (100 - percent) / 100);
- g = (g * (100 - percent) / 100);
- b = (b * (100 - percent) / 100);
- }
- if (r < 0) r = 0;
- if (g < 0) g = 0;
- if (b < 0) b = 0;
- if (r > 255) r = 255;
- if (g > 255) g = 255;
- if (b > 255) b = 255;
- return (rgb & 0xff000000) | (r << 16) | (g << 8) | (b << 0);
- }
- }
-
- class RoundButtonFilter extends ButtonFilter {
- int Xcenter;
- int Ycenter;
- int Yradsq;
- int innerW;
- int innerH;
- int Yrad2sq;
-
- public RoundButtonFilter(boolean press, int p, int b, int w, int h) {
- super(press, p, b, w, h);
- Xcenter = w/2;
- Ycenter = h/2;
- Yradsq = h * h / 4;
- innerW = w - border * 2;
- innerH = h - border * 2;
- Yrad2sq = innerH * innerH / 4;
- }
-
- public void buttonRanges(int y, int ranges[]) {
- int yrel = Math.abs(Ycenter - y);
- int xrel = (int) (Math.sqrt(Yradsq - yrel * yrel) * width / height);
- int xslash = width - (y * width / height);
- ranges[0] = 0;
- ranges[1] = Xcenter - xrel;
- ranges[6] = Xcenter + xrel;
- ranges[7] = width;
- if (y < border) {
- ranges[2] = ranges[3] = ranges[4] = Xcenter;
- ranges[5] = ranges[6];
- } else if (y + border >= height) {
- ranges[2] = ranges[1];
- ranges[3] = ranges[4] = ranges[5] = Xcenter;
- } else {
- int xrel2 = (int) (Math.sqrt(Yrad2sq - yrel * yrel)
- * innerW / innerH);
- ranges[3] = Xcenter - xrel2;
- ranges[4] = Xcenter + xrel2;
- if (y < Ycenter) {
- ranges[2] = ranges[3];
- ranges[5] = ranges[6];
- } else {
- ranges[2] = ranges[1];
- ranges[5] = ranges[4];
- }
- }
- }
-
- private int savedranges[];
- private int savedy;
-
- private synchronized int[] getRanges(int y) {
- if (savedranges == null || savedy != y) {
- if (savedranges == null) {
- savedranges = new int[8];
- }
- buttonRanges(y, savedranges);
- savedy = y;
- }
- return savedranges;
- }
-
- public int filterRGB(int x, int y, int rgb) {
- boolean brighter;
- int percent;
- int i;
- int ranges[] = getRanges(y);
- for (i = 0; i < 7; i++) {
- if (x >= ranges[i] && x < ranges[i+1]) {
- break;
- }
- }
- double angle;
- switch (i) {
- default:
- case 0:
- case 6:
- return rgb & 0x00ffffff;
- case 1:
- brighter = !pressed;
- percent = defpercent;
- break;
- case 5:
- brighter = pressed;
- percent = defpercent;
- break;
- case 2:
- angle = Math.atan2(y - Ycenter, Xcenter - x);
- percent = defpercent - ((int) (Math.cos(angle) * 2 * defpercent));
- if (!pressed) {
- percent = -percent;
- }
- if (percent == 0) {
- return rgb;
- } else if (percent < 0) {
- percent = -percent;
- brighter = false;
- } else {
- brighter = true;
- }
- break;
- case 4:
- angle = Math.atan2(Ycenter - y, x - Xcenter);
- percent = defpercent - ((int) (Math.cos(angle) * 2 * defpercent));
- if (pressed) {
- percent = -percent;
- }
- if (percent == 0) {
- return rgb;
- } else if (percent < 0) {
- percent = -percent;
- brighter = false;
- } else {
- brighter = true;
- }
- break;
- case 3:
- if (!pressed) {
- return rgb & 0x00ffffff;
- }
- brighter = false;
- percent = defpercent;
- break;
- }
- return filterRGB(rgb, brighter, percent);
- }
- }
-